package org.fastsyncer.core.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang.StringUtils;
import org.fastsyncer.common.constant.CommonConstant;
import org.fastsyncer.common.util.ApplicationUtil;
import org.fastsyncer.core.service.PluginService;
import org.fastsyncer.core.util.ClassUtil;
import org.fastsyncer.parser.framework.ConvertFactory;
import org.fastsyncer.plugin.AbstractConvert;
import org.fastsyncer.plugin.Convert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service("PluginService")
public final class PluginServiceImpl implements PluginService {

    private static final Logger logger = LoggerFactory.getLogger(PluginServiceImpl.class);

    // 业务插件
    private static List<Map<String, String>> plugins = new ArrayList<>();

    @Override
    public void start() {
        Class<?> iCls = Convert.class;
        Class<?> absCls = AbstractConvert.class;
        
        // 1、获取系统中的转换器
        // org.fastsyncer.plugin
        String scanPath = iCls.getPackage().getName();
        List<Class<?>> clazzs = ClassUtil.getAllClassByPackageName(scanPath);
        
        // 2、获取插件仓库中的转换器
        this.load(clazzs);
        
        // 3、过滤非转换器实现类
        this.regist(clazzs, iCls, absCls);
    }
    
    @Override
    public List<Map<String, String>> getPlugins() {
        return Collections.unmodifiableList(plugins);
    }

    private void regist(List<Class<?>> clazzs, Class<?> iCls, Class<?> absCls) {
        final String iName = iCls.getName();
        final String absName = absCls.getName();
        int len = clazzs.size();
        Class<?> c = null;
        Class<?>[] is = null;
        String name = null;
        int ilens = 0;
        for (int i = 0; i < len; i++) {
            c = clazzs.get(i);
            name = c.getName();
            // 排除类和接口本身
            if(absName.equals(name) || iName.equals(name)){
                continue;
            }
            
            // 是否继承类
            if (absCls.isAssignableFrom(c)) {
                cache(name);
                continue;
            }
            
            // 是否实现接口
            is = c.getInterfaces();
            ilens = is.length;
            for (int j = 0; j < ilens; j++) {
                if (iName.equals(is[j].getName())) {
                    // 加载插件实现类
                    cache(name);
                    break;
                }
            }
        }
    }
    
    private void load(List<Class<?>> list) {
        // 启动方式是否为开发模式
        String debugModel = ApplicationUtil.getKey(CommonConstant.CONFIG_IS_DEBUG);
        if(StringUtils.equalsIgnoreCase("true", debugModel)){
            return;
        }
        String workspace = ApplicationUtil.getKey(CommonConstant.CONFIG_CURRENT_PATH);
        // 开发环境: C:\fastsyncer\plugins
        // 生产环境: /opt/fastsyncer/plugins
        String dir = new StringBuilder().append(workspace).append(File.separator).append("plugins").toString();
        File file = new File(dir);
        if(!file.isDirectory()){
            return;
        }

        // 取出jar文件中的所有class文件
        File[] files = file.listFiles();
        try {
            for (File f : files) {
                if(f.isDirectory() || !f.getName().endsWith(".jar")) {
                    continue;
                }
                
                @SuppressWarnings("resource")
                JarFile jarFile = new JarFile(f.getAbsolutePath());
                Enumeration<JarEntry> entries = jarFile.entries();

                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    if (entry.getName().endsWith(".class") && !entry.isDirectory()) {
                        // 去掉后面的".class" 获取真正的类名
                        String className = entry.getName().substring(0, entry.getName().length() - 6).replace('/', '.');
                        list.add(Class.forName(className));
                    }
                }
            }
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage());
        } catch (ClassNotFoundException e) {
            logger.error(e.getLocalizedMessage());
        }
    }

    private void cache(final String c) {
        // 解析插件class实例,com.asd.UserConverImpl|com.xx.xx...
        Convert convert = ConvertFactory.getInstance(c);
        // 转换器名称
        String convertName = convert.getConvertName();
        // 默认实例类名称
        convertName = StringUtils.isBlank(convertName) ? c : convertName;
        Map<String, String> plugin = new HashMap<String, String>();
        plugin.put("name", convertName);
        plugin.put("value", c);
        logger.info(c);
        plugins.add(plugin);
    }

}
